package OrderService

import (
	"context"
	"errors"
	"gdshop-back-end-go/client-api/app/request/OrderReq"
	"gdshop-back-end-go/client-api/app/response/CartResp"
	"gdshop-back-end-go/client-api/app/response/MemberResp"
	"gdshop-back-end-go/client-api/app/response/OrderResp"
	toolsDb "gdshop-back-end-go/common/db"
	"gdshop-back-end-go/common/entity"
	"gdshop-back-end-go/common/response"
	"gdshop-back-end-go/common/response/GoodsResp"
	"gdshop-back-end-go/common/tools"
	"gdshop-back-end-go/service-other/GoodsService"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/text/gstr"
	"github.com/gogf/gf/util/gconv"
	"github.com/gogf/gf/util/guid"
	"github.com/gogf/gf/util/gvalid"
	"github.com/syyongx/php2go"
	"strings"
)

// 判断订单当前状态是否可以进行某类型操作
func orderIsOption(orderModel *entity.Order, typeStr string) error {
	text := ""
	yunxuStatus := []int{}

	switch typeStr {
	case "price_change": // 改价，订单状态status = 1代付款 时可修改
		text = "改价"
		yunxuStatus = []int{
			1,
		}
		break
	case "back_pay": // 后台付款，订单状态status = 1代付款 时可 后台付款
		text = "后台付款"
		yunxuStatus = []int{
			1,
		}
		break
	case "member_pay": // 会员付款，订单状态status = 1代付款 时可 后台付款
		text = "会员付款"
		yunxuStatus = []int{
			1,
		}
		break
	case "confirm_goods": // 备货，订单状态status = 2 时可 备货
		text = "备货"
		yunxuStatus = []int{
			2,
		}
		break
	case "confirm_order": // 确认收货，订单状态status = 4 时可 确认收货
		text = "后台付款"
		yunxuStatus = []int{
			4,
		}
		break
	case "cancel_goods": // 取消备货，订单状态status = 3 时可 取消备货
		text = "取消备货"
		yunxuStatus = []int{
			3,
		}
		break
	case "send_express": // 发货，订单状态status = 3 时可 发货
		text = "发货"
		yunxuStatus = []int{
			3,
		}
		break
	case "cancel_express": // 取消发货，订单状态status = 3 4 时可 取消发货
		text = "取消发货"
		yunxuStatus = []int{
			3, 4,
		}
		break
	case "close_order": // 确认收货，订单状态status = 4 时可 确认收货
		text = "关闭订单"
		yunxuStatus = []int{
			1, 2, 3,
		}
		break
	}

	for _, item := range yunxuStatus {
		// 只要有一个状态符合，就可以进行操作
		if item == orderModel.Status {
			return nil
		}
	}

	return errors.New("当前订单状态不允许" + text)
}
func GetOrderModel(ctx context.Context, orderId int) *entity.Order {
	return getOrderModel(ctx, orderId)
}
func getOrderModel(ctx context.Context, orderId int) *entity.Order {
	var params *entity.Order
	err := toolsDb.GetUnSafaTableAddDeleteWhere(ctx, "order").Where("id", orderId).Struct(&params)
	if err != nil {
		return nil
	}

	return params
}
func getOrderAndPriceModel(ctx context.Context, orderId int) *entity.OrderAndPrice {
	var params *entity.OrderAndPrice
	err := toolsDb.GetUnSafaTable(ctx, "order").As("o").Where("o.delete_at < 1 AND o.id = ?",
		orderId,
	).LeftJoin("order_price op", "o.id = op.order_id").Fields(
		"o.*,IFNULL(op.dispatch_price_change,0) AS dispatch_price_change,IFNULL(op.total_price_change,0) AS total_price_change",
	).Struct(&params)
	if err != nil {
		return nil
	}

	return params
}

func GetStatusTextArr() g.MapIntStr {
	return map[int]string{
		0:  "关闭",
		1:  "待付款",
		2:  "待备货",
		3:  "待发货",
		4:  "待收货",
		5:  "待评价",
		99: "已完成",
	}
}

func GetRefundStatusTextArr() g.MapIntStr {
	return map[int]string{
		0:  "正常",
		1:  "待处理",
		2:  "驳回",
		3:  "同意",
		99: "完成",
	}
}

func GiveBackCouponByOrderId(ctx context.Context, orderId int) *response.JsonResponse {
	var oscList []*entity.OrderSubCoupon
	err := toolsDb.GetUnSafaTable(ctx, "order_sub_coupon").
		Where("order_id", orderId).Structs(&oscList)
	if err != nil {
		return response.FailByRequestMessage(nil, err.Error())
	}
	if len(oscList) > 0 {
		mcIds := []int{}
		for _, item := range oscList {
			mcIds = append(mcIds, item.MemberCouponId)
		}
		update, err := toolsDb.GetUnSafaTable(ctx, "member_coupon").Where("id IN (?)", mcIds).Update(g.Map{
			"use_time": 0,
		})
		if err != nil {
			return response.FailByRequestMessage(nil, err.Error())
		}
		affected, err := update.RowsAffected()
		if err != nil {
			return response.FailByRequestMessage(nil, err.Error())
		}
		if int(affected) != len(mcIds) {
			g.Log().Ctx(ctx).Cat("CloseNoPayOrder").Async().Error("退还优惠券出错 orderId:" + gconv.String(orderId))
			return response.FailByRequestMessage(nil, "退还优惠券出错")
		}

		return response.SuccessByRequestMessage(nil, "成功")
	}

	return response.SuccessByRequestMessage(nil, "成功，未使用优惠券")
}

func getGoodsKeyString(GoodsList []*OrderReq.OrderSubItem) string {
	var str []string
	for _, goods := range GoodsList {
		str = append(str, goods.GoodsName)
	}
	return strings.Join(str, "-")
}

func getCategoryIds(cates string) []int {
	tmps := gstr.SplitAndTrim(cates, ",")
	var fanhui []int
	for _, item := range tmps {
		fanhui = append(fanhui, gconv.Int(item))
	}
	return fanhui
}

// 检查goods，单条检测
func checkGoods(ctx context.Context, parames *OrderReq.GoodsItem, storeId int) (*OrderReq.OrderSubItem, error) {
	// 判断基本参数
	rules := map[string]string{
		"GoodsId":       "required|integer|min:1",
		"GoodsOptionId": "required|integer|min:1",
		"GoodsNum":      "required|integer|min:1",
	}
	msgs := map[string]interface{}{
		"GoodsId": map[string]string{
			"required": "请选择商品",
			"integer":  "商品ID格式错误",
			"min":      "商品ID格式错误",
		},
		"GoodsOptionId": map[string]string{
			"required": "请选择商品规格",
			"integer":  "商品规格ID格式错误",
			"min":      "商品规格ID格式错误",
		},
		"GoodsNum": map[string]string{
			"required": "请填写商品数量",
			"integer":  "商品数量格式错误",
			"min":      "数量不能小于1",
		},
	}

	if e := gvalid.CheckStruct(ctx, parames, rules, msgs); e != nil {
		//g.Dump(e.Maps())
		return nil, e
	}

	// 先找出是否有当前商品
	goodsModel := GoodsService.GetGoodsModelRaw(ctx, parames.GoodsId)
	if goodsModel == nil {
		return nil, errors.New("找不到goods数据，ID：" + gconv.String(parames.GoodsId))
	}
	// 检测店铺ID是否相等
	if goodsModel.StoreId != storeId {
		return nil, errors.New("店铺ID不相等，ID：" + gconv.String(parames.GoodsId))
	}
	// 判断是否是上架状态
	if goodsModel.Status != 1 {
		return nil, errors.New("商品《" + goodsModel.GoodsName + "》已下架")
	}
	optionModel := GoodsService.GetGoodsOptionsById(ctx, int(parames.GoodsOptionId))
	if optionModel == nil {
		return nil, errors.New("找不到goods_option数据，ID：" + gconv.String(parames.GoodsOptionId))
	}

	// 判断当前规格是否指向当前商品
	if optionModel.GoodsId != int(goodsModel.Id) {
		g.Log().Error("GoodsId:" + gconv.String(goodsModel.Id) + " optionModel:" + gconv.String(optionModel))
		return nil, errors.New("GoodsId不匹配，ID：" + gconv.String(parames.GoodsOptionId))
	}

	// 数量是否超库存
	if parames.GoodsNum > optionModel.Stock {
		g.Log().Error("GoodsNum:" + gconv.String(parames.GoodsNum) + " optionModel:" + gconv.String(optionModel))
		return nil, errors.New("《" + optionModel.Title + "》规格库存不足")
	}
	// 压入规则规格
	goodsModel.Options = []*GoodsResp.GoodsOption{}
	goodsModel.Options = append(goodsModel.Options, optionModel)

	orderSubItem := OrderReq.OrderSubItem{
		Total: parames.GoodsNum,
		// 先计算出总价，后面不再计算
		TotalPrice: optionModel.SellPrice * int64(parames.GoodsNum),
		Details:    *goodsModel,
	}
	// 2021.07.17 增加数据标识符
	orderSubItem.SellPrice = optionModel.SellPrice
	orderSubItem.Hash = guid.S()
	orderSubItem.CategoryId = getCategoryIds(orderSubItem.Cates)
	orderSubItem.OptionId = int(optionModel.Id)

	// 2021.09.13 计算活动价格

	return &orderSubItem, nil
}

// OrderSubItemModelToOrderSubCoupon model 转换
func OrderSubItemModelToOrderSubCoupon(item *OrderReq.OrderSubItem, couponId, memberCouponId int) OrderReq.OrderSubCoupon {
	return OrderReq.OrderSubCoupon{
		Hash:           item.Hash,
		StoreId:        item.StoreId,
		GoodsId:        int(item.Id),
		Price:          item.SellPrice,
		Num:            int64(item.Total),
		TotalPrice:     item.TotalPrice,
		CouponId:       couponId,
		MemberCouponId: memberCouponId,
		GoodsOptionId:  item.OptionId,
	}
}

// 计算单张优惠券使用的结果，返回已使用的结果
func calcCouponOne(orderSubs []*OrderReq.OrderSubItem,
	coupon *MemberResp.MemberCoupon) []OrderReq.OrderSubCoupon {
	var ids []int
	// 防止修改状态
	ids = coupon.UseSrcIdsIntArr

	// 先保存下可使用的子订单
	var canUseOrderSubs []OrderReq.OrderSubCoupon
	// 适用商品类型 0全部可用 1指定分类可用 2指定分类不可用 3指定商品可用 4指定商品不可用 5指定店铺可用 6指定店铺不可用
	for _, item := range orderSubs {
		if coupon.UseGoodsType == 0 { // 全部可用
			canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
			continue
		}
		if coupon.UseGoodsType == 1 { // 1指定分类可用
			for _, cid := range item.CategoryId {
				if php2go.InArray(cid, ids) {
					//  包含在可用里面
					canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				}
			}
			continue
		}
		if coupon.UseGoodsType == 2 { // 2指定分类不可用
			for _, cid := range item.CategoryId {
				if !php2go.InArray(cid, ids) {
					//  包含在可用里面
					canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				}
			}
			continue
		}
		if coupon.UseGoodsType == 3 { // 3指定商品可用
			if php2go.InArray(gconv.Int(item.Id), ids) {
				//  包含在可用里面
				canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				continue
			}
		}
		if coupon.UseGoodsType == 4 { // 4指定商品不可用
			if !php2go.InArray(gconv.Int(item.Id), ids) {
				//  包含在可用里面
				canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				continue
			}
		}
		if coupon.UseGoodsType == 5 { // 5指定店铺可用
			if php2go.InArray(item.StoreId, ids) {
				//  包含在可用里面
				canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				continue
			}
		}
		if coupon.UseGoodsType == 6 { // 6指定店铺不可用
			if !php2go.InArray(item.StoreId, ids) {
				//  包含在可用里面
				canUseOrderSubs = append(canUseOrderSubs, OrderSubItemModelToOrderSubCoupon(item, coupon.Id, coupon.MemberCouponId))
				continue
			}
		}
	}
	// 排除不可用的
	if coupon.ExcludeGoodsIds != nil {
		excludeGoodsIds := coupon.ExcludeGoodsIds.Slice()
		for k, item := range canUseOrderSubs {
			if php2go.InArray(item.GoodsId, excludeGoodsIds) {
				canUseOrderSubs = append(canUseOrderSubs[:k], canUseOrderSubs[k+1:]...)
			}
		}
	}
	// 统计总可用子订单的总金额
	var canUseTotalPrice int64 = 0
	// 统计总可用子订单的总件数
	var canUseTotalNum int64 = 0

	for _, item := range canUseOrderSubs {
		canUseTotalPrice += item.TotalPrice
		canUseTotalNum += item.Num
	}
	// 判断是否有门槛
	if coupon.IsThreshold == 1 {
		// 判断是否足够门槛
		switch coupon.CouponType {
		case 1, 2:
			// 满金额
			if coupon.ThresholdMoney > canUseTotalPrice {
				// 不符合，返回空
				return []OrderReq.OrderSubCoupon{}
			}
			break
		case 3, 4: // 满件
			if int64(coupon.ThresholdNum) > canUseTotalNum {
				// 不符合，返回空
				return []OrderReq.OrderSubCoupon{}
			}
			break
		}
	} else {
		// 无门槛时，需要把 ThresholdMoney ThresholdNum 清 0
		coupon.ThresholdMoney = 0
		coupon.ThresholdNum = 0
	}

	switch coupon.CouponType {
	case 1, 3: // 1满金额减；3满件减
		for k, item := range canUseOrderSubs {
			canUseOrderSubs[k].Discount = int64(tools.FloatRound(float64(item.TotalPrice)/float64(canUseTotalPrice)*(float64(coupon.DiscountMoney)/100.00), 2) * 100.00)
			canUseOrderSubs[k].Paid = item.TotalPrice - canUseOrderSubs[k].Discount
			// 如果优惠金额大于订单金额，修正
			if canUseOrderSubs[k].Paid < 1 {
				canUseOrderSubs[k].Paid = 0
				canUseOrderSubs[k].Discount = item.TotalPrice
			}
		}
		break
	case 2, 4: // 2满金额折；4满件折
		for k, item := range canUseOrderSubs {
			canUseOrderSubs[k].Paid = int64(tools.FloatRound(float64(item.TotalPrice)*(float64(coupon.DiscountRatio)/10000.00), 2))
			canUseOrderSubs[k].Discount = item.TotalPrice - canUseOrderSubs[k].Paid
		}
		break
	}
	// 返回使用了优惠券的子订单集合，方便后续做日志
	return canUseOrderSubs
}

// 按商家检查
func CheckStore(ctx context.Context, parames *OrderReq.SubmitItem, useCouponList []*MemberResp.MemberCoupon) (*OrderReq.CheckSubmitItem, error) {
	if len(parames.GoodsList) < 1 {
		return nil, errors.New("商品为空")
	}
	var totalPrice int64 = 0
	var results = OrderReq.CheckSubmitItem{}
	results.StoreId = parames.StoreId
	for _, goods := range parames.GoodsList {
		data, err := checkGoods(ctx, goods, parames.StoreId)
		if err != nil {
			return nil, err
		}
		results.GoodsList = append(results.GoodsList, data)
		// 计算总价
		totalPrice += int64(goods.GoodsNum) * data.Options[0].SellPrice
		// 计算运费

	}
	results.GoodsKey = getGoodsKeyString(results.GoodsList)

	// 检测活动

	// 检测优惠券
	var useOrderSubs []OrderReq.OrderSubCoupon
	for _, item := range useCouponList {
		useOrderSubs = append(useOrderSubs, calcCouponOne(results.GoodsList, item)...)
	}
	results.UseCouponOrderSubs = useOrderSubs

	// 检测发票
	// 原订单总价（商品合计，未包含任何优惠）单位分
	results.OriginalTotalPrice = totalPrice
	// 计算总价 减去全部优惠
	for _, item := range useOrderSubs {
		totalPrice -= item.Discount
	}
	results.TotalPrice = totalPrice
	return &results, nil
}

// DoCreateCartData 从购物车过来的，分组下单
func DoCreateCartData(ctx context.Context, parames *OrderReq.Create) (*OrderResp.Create, error) {
	cartIds := []int{}
	for _, item := range parames.CartData {
		cartIds = append(cartIds, item.CartIds...)
	}
	// 防止重复
	if tools.DuplicateInArray(cartIds) > 0 {
		return nil, errors.New("cart_id 包含重复ID")
	}
	// 批量取出购物车信息
	cartList := []*CartResp.Details{}
	err := toolsDb.GetUnSafaTableAddDeleteWhere(
		ctx, "member_cart",
	).Where("member_id=? AND id IN (?)", parames.MemberId, cartIds).Structs(&cartList)
	if err != nil {
		return nil, err
	}
	if len(cartList) < 1 {
		return nil, errors.New("找不到购物车中的商品")
	}

	orderList := []*OrderResp.OrderItem{}

	// 组装下单数据
	for _, item := range parames.CartData {
		var tmpOrderData []*OrderReq.GoodsItem
		for _, cc := range cartList {
			if php2go.InArray(cc.Id, item.CartIds) {
				tmpOrderData = append(tmpOrderData, &OrderReq.GoodsItem{
					GoodsId:       cc.GoodsId,
					GoodsNum:      cc.Total,
					GoodsOptionId: uint(cc.GoodsOptionId),
				})
			}
		}
		createByGroup, err := DoCreateByGroup(ctx, tmpOrderData, parames.MemberId, item.CouponIds, item.ActivityId)
		if err != nil {
			return nil, err
		}
		orderList = append(orderList, createByGroup)
	}

	return &OrderResp.Create{
		OrderList: orderList,
		Discounts: []*OrderResp.DiscountItem{},
	}, nil
}

func getGoodsStoreName(storeId int) string {
	if storeId == 0 {
		return "自营"
	}

	return "第三方商家"
}

func GetOrderSubByOrderId(ctx context.Context, orderId int) []*OrderResp.SubOrder {
	var subOrderList []*OrderResp.SubOrder
	err := toolsDb.GetUnSafaTableAddDeleteWhere(ctx, "order_sub").Order("id DESC").Where(
		"order_id=?",
		orderId,
	).Structs(&subOrderList)
	if err != nil {
		g.Log().Async().Error("GetOrderSubByOrderId错误 ", orderId, err.Error())
		return nil
	}

	for _, item := range subOrderList {
		item.ThumbsArr = tools.GetGoodsThumbs(item.GoodsThumbs)
		if len(item.ThumbsArr) > 0 {
			item.CoverPhoto = item.ThumbsArr[0]
		} else {
			// 设置默认图片
		}
	}

	return subOrderList
}

func OrderIsExpress(ctx context.Context, orderId int) bool {
	count, err := toolsDb.GetUnSafaTable(ctx, "order_express").Distinct().As("oe").
		LeftJoin("order_sub os", "oe.order_sub_id = os.id").Where(
		"oe.delete_at < 1 AND (os.order_id = ? OR oe.order_id = ?)", orderId,
		orderId,
	).Fields(
		"1").Count()
	if err != nil {
		return false
	}

	return count > 0
}

func OrderIsShowPrimary(status int) bool {
	switch status {
	case 5:
		return true
	case 4:
		return true
	case 1:
		return true
	default:
		return false
	}
}

func GetOrderTipsList(orderId int) []*OrderResp.OrderTips {
	if orderId%2 == 1 {
		return []*OrderResp.OrderTips{
			&OrderResp.OrderTips{
				Title:  "15天价保",
				Remark: "1.26-2.9为保价服务期",
				Status: "已结束",
			},
		}
	} else {
		return []*OrderResp.OrderTips{}
	}

}
